/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.resolver.spi;
// Java 2 standard packages
import java.util.*;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
// Third party packages
import org.apache.log4j.Logger;
/**
* A dummy implementation of the {@link XAResource} interface which logs the
* calls made to it, but otherwise ignores them.
*
* @created 2004-05-12
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
* @version $Revision: 1.8 $
* @modified $Date: 2005/01/05 04:58:50 $
* @maintenanceAuthor $Author: newmana $
* @copyright ©2004 <a href="http://www.tucanatech.com/">Tucana
* Technoogies, Inc.</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class DummyXAResource implements XAResource
{
/** Logger. */
private static final Logger logger = Logger.getLogger(DummyXAResource.class.getName());
/**
* Map from keyed from the {@link Integer} value of the various flags
* defined in {@link XAResource} and mapping to the formatted name for that
* flag.
*/
protected final static Map<Integer,String> flagMap = new HashMap<Integer,String>();
static {
flagMap.put(new Integer(XAResource.TMENDRSCAN), "TMENDRSCAN");
flagMap.put(new Integer(XAResource.TMFAIL), "TMFAIL");
flagMap.put(new Integer(XAResource.TMJOIN), "TMJOIN");
flagMap.put(new Integer(XAResource.TMONEPHASE), "TMONEPHASE");
flagMap.put(new Integer(XAResource.TMRESUME), "TMRESUME");
flagMap.put(new Integer(XAResource.TMSTARTRSCAN), "TMSTARTRSCAN");
flagMap.put(new Integer(XAResource.TMSUCCESS), "TMSUCCESS");
flagMap.put(new Integer(XAResource.TMSUSPEND), "TMSUSPEND");
}
/** The transaction timeout value in seconds. */
protected int transactionTimeout = 0;
//
// Constructor
//
/**
* Construct a {@link DummyXAResource} with a default 10 second transaction timeout.
*/
public DummyXAResource() {
this(10);
}
/**
* Construct a {@link DummyXAResource} with a specified transaction timeout.
*
* @param transactionTimeout transaction timeout period, in seconds
*/
public DummyXAResource(int transactionTimeout) {
if (logger.isDebugEnabled()) {
logger.debug("Creating " + getClass().getName() + " with timeout " + transactionTimeout);
}
this.transactionTimeout = transactionTimeout;
}
//
// Methods implementing XAResource
//
public void commit(Xid xid, boolean onePhase) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Commit xid=" + System.identityHashCode(xid) + " onePhase=" + onePhase);
}
}
public void end(Xid xid, int flags) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("End xid=" + System.identityHashCode(xid) + " flags=" + formatFlags(flags));
}
}
public void forget(Xid xid) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Forget xid=" + System.identityHashCode(xid));
}
}
public int getTransactionTimeout() throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Get transaction timeout: " + transactionTimeout);
}
return transactionTimeout;
}
public boolean isSameRM(XAResource xaResource) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Is same resource manager? " + (xaResource == this));
}
return xaResource == this;
}
public int prepare(Xid xid) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Prepare " + System.identityHashCode(xid));
}
return XA_OK;
}
public Xid[] recover(int flag) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Recover flag=" + formatFlags(flag));
}
throw new XAException(XAException.XAER_RMERR);
}
public void rollback(Xid xid) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Rollback " + System.identityHashCode(xid));
}
}
public boolean setTransactionTimeout(int transactionTimeout) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Set transaction timeout: " + transactionTimeout);
}
this.transactionTimeout = transactionTimeout;
return true;
}
public void start(Xid xid, int flags) throws XAException {
if (logger.isDebugEnabled()) {
logger.debug("Start " + System.identityHashCode(xid) + " flags=" + formatFlags(flags));
}
}
//
// Internal methods
//
/**
* @param t the exception
* @return true if <var>t</var> is an XAException that represents a heuristic completion
*/
public static boolean isHeuristic(Throwable t) {
return (t instanceof XAException) && isHeuristic(((XAException)t).errorCode);
}
/**
* @param errorCode the xa error code
* @return true if <var>errorCode</var> represents a heuristic completion
*/
public static boolean isHeuristic(int errorCode) {
return (errorCode == XAException.XA_HEURHAZ || errorCode == XAException.XA_HEURCOM ||
errorCode == XAException.XA_HEURRB || errorCode == XAException.XA_HEURMIX);
}
/**
* @param t the exception
* @return true if <var>t</var> is an XAException that represents a rollback
*/
public static boolean isRollback(Throwable t) {
return (t instanceof XAException) && isRollback(((XAException)t).errorCode);
}
/**
* @param errorCode the xa error code
* @return true if <var>errorCode</var> represents a rollback
*/
public static boolean isRollback(int errorCode) {
return (errorCode >= XAException.XA_RBBASE && errorCode <= XAException.XA_RBEND);
}
/**
* Format an xid for printing.
*
* @param xid the xid to format
* @return a string representation of the xid
*/
protected static final String formatXid(Xid xid) {
return "[" + xid.getFormatId() + ":" + Arrays.hashCode(xid.getGlobalTransactionId()) + ":" +
Arrays.hashCode(xid.getBranchQualifier()) + "]";
}
/**
* Format bitmasks defined by {@link XAResource}.
*
* @param flags a bitmask composed from the constants defined in {@link XAResource}
* @return a formatted representation of the <var>flags</var>
*/
protected static final String formatFlags(int flags) {
// Short-circuit evaluation if we've been explicitly passed no flags
if (flags == XAResource.TMNOFLAGS) {
return "TMNOFLAGS";
}
StringBuilder buffer = new StringBuilder();
// Add any flags that are present
for (Map.Entry<Integer,String> entry : flagMap.entrySet()) {
int entryFlag = entry.getKey().intValue();
// If this flag is present, add it to the formatted output and remove
// from the bitmask
if ((entryFlag & flags) == entryFlag) {
if (buffer.length() > 0) {
buffer.append(",");
}
buffer.append(entry.getValue());
flags &= ~entryFlag;
}
}
// We would expect to have removed all flags by this point
// If there's some unknown flag we've missed, format it as hexadecimal
if (flags != 0) {
if (buffer.length() > 0) {
buffer.append(",");
}
buffer.append("0x").append(Integer.toHexString(flags));
}
return buffer.toString();
}
}